package com.video.commons.task;

import com.video.entity.Task;
import com.video.service.task.ITaskService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 *
 * 任务状态管理工具类
 *
 * 变更任务状态，存储的数据结构：
 *
 * //正在运行的任务集合
 * set类型：
 * "runtask":[任务id1, 任务id2...]
 *
 * //status - 任务状态  0-任务空闲  1-执行中 2-停止 3-暂停
 * //type - 任务类型 1-每天任务  2-每周任务  3-一次任务
 * hash类型：
 * "taskid": {"status":0/1/2/3, "map3":"当前曲目", "curtime":"当前执行时长", "startDate":"任务开始时间"
 *          "duration":"当前歌曲时长", "allduration":"任务总时长", "type":1/2/3}
 *
 * hash类型：
 * "clientid": {"status":0/1/2/3, "map3":"当前曲目"}
 *
 * @version 1.0
 * @user ken
 * @date 2019/5/26 21:52
 */
@Component
@Lazy
public class TaskStatusUtil {

    @Autowired
    private StringRedisTemplate redisTemplate;

    @Autowired
    private ITaskService taskService;


    /**
     * 查询任务状态
     * @return
     */
    public List<Map<String, Object>> queryTaskStatus(String[] taskids){
        //状态列表
        List<Map<String, Object>> rlist = new ArrayList();
        //循环任务id列表
        for (String taskid : taskids) {
            Map<String, Object> newMap = new HashMap<>();
            //任务id
            newMap.put("taskid", taskid);
            //当前曲目
            newMap.put("mp3", redisTemplate.opsForHash().get(KEYS.TASK_KEY + taskid, "mp3"));
            //当前状态
            newMap.put("status", redisTemplate.opsForHash().get(KEYS.TASK_KEY + taskid, "status"));
            //任务类型
            newMap.put("type", redisTemplate.opsForHash().get(KEYS.TASK_KEY + taskid, "type"));
            //当前进度
            newMap.put("curtime", redisTemplate.opsForHash().get(KEYS.TASK_KEY + taskid, "curtime"));
            //当前歌曲时长
            newMap.put("duration", redisTemplate.opsForHash().get(KEYS.TASK_KEY + taskid, "duration"));
            //总时长
            newMap.put("allduration", redisTemplate.opsForHash().get(KEYS.TASK_KEY + taskid, "allduration"));
            //获取任务开始时间
            newMap.put("startDate", redisTemplate.opsForHash().get(KEYS.TASK_KEY + taskid, "startDate"));

            rlist.add(newMap);
        }
        return rlist;
    }

    /**
     * 根据终端列表查询当前任务最新状态
     * @return
     */
    public List<Map<String, Object>> queryClientsStatus(String[] uids){
        //终端任务列表
        List<Map<String, Object>> clist = new ArrayList();
        //循环终端id
        for (String uid : uids) {
            //设置终端信息
            Map<String, Object> newMap = new HashMap<>();
            //终端id
            newMap.put("uid", uid);
            //终端曲目
            newMap.put("mp3", redisTemplate.opsForHash().get(KEYS.CLIENT_KEY + uid, "mp3"));
            //终端状态
            String status = (String) redisTemplate.opsForHash().get(KEYS.CLIENT_KEY + uid, "status");
            newMap.put("status", status == null ? 0 : Integer.parseInt(status));

            clist.add(newMap);
        }
        return clist;
    }

    /**
     * 修改任务/终端状态
     * @param taskid - 任务id
     * @param status - 状态码 0-任务空闲  1-执行中 2-停止 3-暂停
     * @param mp3 - 当前曲目
     * @param duration - 任务进度
     * @param startDate - 任务开始时间
     * @param users - 终端列表
     */
    public void updateTaskStatus(String taskid, Integer status, String mp3, Integer duration, String startDate, String[] users){
        if (taskid != null && !taskid.equals("")) {
            //判断redis中是否有该任务id
            if (!redisTemplate.hasKey(KEYS.TASK_KEY + taskid)) {
                Task task = taskService.getByTaskId(taskid);
                //如果没有该任务，则不处理
                if (task == null) {
                    return;
                }

                //保存任务状态
                addTaskStatus(task);
            }

            if (status == 1) {
                //设置为执行中
                actionTask(taskid);
            } else {
                //非执行中
                stopTask(taskid);
            }

            if (status == 2) {
                //停止状态
                //当前进度，默认为0
                redisTemplate.opsForHash().put(KEYS.TASK_KEY + taskid, "curtime", 0 + "");
            }

            //更新任务状态
            redisTemplate.opsForHash().put(KEYS.TASK_KEY + taskid, "status", status + "");
            //更新当前曲目
            redisTemplate.opsForHash().put(KEYS.TASK_KEY + taskid, "mp3", mp3);
            //更新总时长
            redisTemplate.opsForHash().put(KEYS.TASK_KEY + taskid, "duration", duration + "");
            //设置任务开始时间
            redisTemplate.opsForHash().put(KEYS.TASK_KEY + taskid, "startDate", startDate);

            //判断任务类型
            int type = Integer.parseInt((String) redisTemplate.opsForHash().get(KEYS.TASK_KEY + taskid, "type"));
            //如果是一次性任务，并且又是停止状态
            if (type == 3 && status == 2){
                //设置1分钟的过期时间
                redisTemplate.expire(KEYS.TASK_KEY + taskid, 1, TimeUnit.MINUTES);
            }
        }

        //修改终端状态
        if (users != null) {
            for (String user : users) {
                //更新终端状态
                //添加终端状态，默认为0 - 空闲
                redisTemplate.opsForHash().put(KEYS.CLIENT_KEY + user, "status", status + "");
                //当前进度，默认为0
                redisTemplate.opsForHash().put(KEYS.CLIENT_KEY + user, "mp3", mp3);
            }
        }
    }

    /**
     * 给运行中的任务添加进度值
     *
     * 每秒触发一次
     */
    @Scheduled(cron = "0/1 * * * * *")
    @Async
    public void addCurtimeRunTask(){

        //获取运行任务的列表
        Set<String> tasks = redisTemplate.opsForSet().members(KEYS.RUN_TASK);

        //循环
        if (tasks != null && tasks.size() > 0){
            for (String task : tasks) {
                //判断任务是否存在
                if(redisTemplate.hasKey(KEYS.TASK_KEY + task)) {

                    //获得任务进度以及总时长
                    int allduration = Integer.parseInt((String) redisTemplate.opsForHash().get(KEYS.TASK_KEY + task, "allduration"));
                    int curtime = Integer.parseInt((String) redisTemplate.opsForHash().get(KEYS.TASK_KEY + task, "curtime"));

                    if (curtime < allduration)
                        //当前进度 + 1
                        redisTemplate.opsForHash().increment(KEYS.TASK_KEY + task, "curtime", 1);
                } else {
                    //将任务从运行列表中移除
                    redisTemplate.opsForSet().remove(KEYS.RUN_TASK, task);
                }
            }
        }
    }

    /**
     * 保存任务状态
     */
    public void addTaskStatus(Task task){
        //如果是第一次添加，就设置部分信息
        if(!redisTemplate.hasKey(KEYS.TASK_KEY + task.getTaskid())) {
            //添加任务状态，默认为0 - 空闲任务
            redisTemplate.opsForHash().put(KEYS.TASK_KEY + task.getTaskid(), "status", 0 + "");
            //当前进度，默认为0
            redisTemplate.opsForHash().put(KEYS.TASK_KEY + task.getTaskid(), "curtime", 0 + "");
        }

        //不管第几次添加，都修改状态和总时长
        //添加任务类型
        redisTemplate.opsForHash().put(KEYS.TASK_KEY + task.getTaskid(), "type", task.getPlayOrder() + "");
        //保存任务总时长
        redisTemplate.opsForHash().put(KEYS.TASK_KEY + task.getTaskid(), "allduration", task.getDuration() + "");
    }

    /**
     * 删除任务状态
     * @param taskId
     */
    public void delTaskStatus(String taskId){
        //删除redis
        if (taskId != null)
            redisTemplate.delete(KEYS.TASK_KEY + taskId);
    }

    /**
     * 执行任务
     * @param taskId
     */
    public void actionTask(String taskId){
        //添加到运行状态列表中
        if (taskId != null)
            redisTemplate.opsForSet().add(KEYS.RUN_TASK, taskId);
    }

    /**
     * 停止任务
     */
    public void stopTask(String taskId){
        //从运行状态列表移除
        if (taskId != null)
            redisTemplate.opsForSet().remove(KEYS.RUN_TASK, taskId);
    }

    /**
     * 是否执行
     * @param taskId
     * @return
     */
    public boolean isAction(String taskId){
        return redisTemplate.opsForSet().isMember(KEYS.RUN_TASK, taskId);
    }


    /**
     * redis中的相关key
     */
    private interface KEYS{
        String RUN_TASK = "run_task";
        String TASK_KEY = "task_";
        String CLIENT_KEY = "client_";
    }

}
